package management;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.MidiDevice.Info;

/**
 * Singleton class to manage Midi Devices and Receivers.
 * 
 * @author Dylan James
 *
 */
public class MidiManager {
	private static MidiManager instance;

	private static MidiDevice midiYoke1;
	private static Receiver midiYoke1Rec;
	
	private ShortMessage muteMessage;
	private ShortMessage unmuteMessage;

	public enum MidiVoices{
		Drone (1),
		Arpeggio (2),
		Harmony (3),
		SampleBank (4);
		
		public int ChannelNumber;
		
		MidiVoices(int chanNum)
		{
			this.ChannelNumber = chanNum;
		}
	}
	
	/**
	 * @return An instance of the MidiManager
	 */
	public static MidiManager getMidiManager()
	{
		if (instance == null)
		{
			instance = new MidiManager();
		}

		return instance;
	}

	private MidiManager()
	{
		// Set up Midi Devices

		int i;
		Info[] infos = MidiSystem.getMidiDeviceInfo(); // Get all the available Midi Devices

		// Loop through each info. Check for MidiYoke 1, and get the index.
		for (i = 0; i < infos.length; i++){			
			if (infos[i].toString().contains("Out To MIDI Yoke:  1"))
			{
				// If so, we have the right midi device.
				try {
					// Get the found midi device and store it in midiYoke1
					midiYoke1 = MidiSystem.getMidiDevice(infos[i]);

					// Open the found Midi Device.
					midiYoke1.open();

					// Get a receiver from the device
					midiYoke1Rec = midiYoke1.getReceiver();
					
					break; // If we got this far, we've found what we were looking for, so exit loop.
					
				} catch (MidiUnavailableException e) {
					e.printStackTrace();
				}
			}
		}
		
		muteMessage = new ShortMessage();
		try {
			muteMessage.setMessage(ShortMessage.CONTROL_CHANGE, 1, 1, 127);
		} catch (InvalidMidiDataException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		unmuteMessage = new ShortMessage();
		try {
			unmuteMessage.setMessage(ShortMessage.CONTROL_CHANGE, 1, 1, 32);
		} catch (InvalidMidiDataException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * @return The Midi Device corresponding to Midi Yoke 1.
	 */
	public MidiDevice getMidiYoke1()
	{
		return midiYoke1;
	}

	/**
	 * @return The receiver bound to Midi Yoke 1.
	 */
	public Receiver getMidiYoke1Receiver()
	{
		return midiYoke1Rec;
	}
	
	/**
	 * Sends a message to Midi Yoke 1 corresponding to setting the Buzz master volume to 127.
	 */
	public void Mute()
	{
		System.out.println("Mute");
		getMidiYoke1Receiver().send(muteMessage, 0);
	}
	
	/**
	 * Sends a message to Midi Yoke 1 corresponding to setting the Buzz master volume to 32.
	 */
	public void Unmute()
	{
		System.out.println("Unmute");
		getMidiYoke1Receiver().send(unmuteMessage, 0);
	}

	/**
	 * Call this function when the application is exiting.
	 * Cleans up the Midi Devices that have been opened.
	 */
	public static void OnAppExit()
	{
		if (midiYoke1 != null)
		{
			if (midiYoke1Rec != null)
			{
				midiYoke1Rec.close();
			}

			midiYoke1.close();
		}
	}
}
